package com.aispeech.rcprvd.utils;

import android.app.Application;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.res.XmlResourceParser;
import android.hardware.usb.UsbDevice;
import android.text.TextUtils;
import android.util.Log;

import com.aispeech.rcprvd.R;
import com.aispeech.rcprvd.RemoteDevice;
import com.aispeech.rcprvd.jni.RcNativeProcessJni;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import androidx.annotation.NonNull;

import static com.aispeech.rcprvd.utils.RcPrvdConst.RCDevSource;

public class RemoteDeviceUtils {
    private final static String TAG = "RemoteDeviceUtils";

    public static RemoteDevice checkCurrentRemoteDevice(int devSource, @NonNull Application context) {
        Log.d(TAG, "checkCurrentRemoteDevice: devSource = " + devSource);
        RemoteDevice remoteDevice = null;
        switch (devSource) {
            case RCDevSource.BLE_AUDIO:
//                remoteDevice = checkAudioDevice(context);
                break;
            case RCDevSource.NANO_HID:
                remoteDevice = checkUsbDevice(context);
                break;
            case RCDevSource.NANO_BLE_NODE:
                remoteDevice = checkBleNodeDevice(context);
                break;
            case RCDevSource.JINJU_BLE_GATT:
                remoteDevice = checkBleGattDevice(context);
                break;
        }
        return remoteDevice;
    }

    private static RemoteDevice checkBleGattDevice(@NonNull Application context) {
        Set<BluetoothDevice> bondedBleDevices = getBondedBleDevices(context);
        if (null != bondedBleDevices && bondedBleDevices.size() > 0) {
            List<RemoteDevice> supportRemoteDeviceList = getSupportRemoteDeviceList(context);
            if (null == supportRemoteDeviceList || supportRemoteDeviceList.size() <= 0) {
                Log.w(TAG, "checkBleGattDevice: supportRemoteDeviceList is empty");
                return null;
            }
            for (RemoteDevice dev : supportRemoteDeviceList) {
                for (BluetoothDevice device : bondedBleDevices) {
                    if (device.getName().equals(dev.getDevName())) {
                        Log.d(TAG, "checkBleGattDevice: found target device " + dev.getDevName());
                        return dev;
                    } else {
                        Log.i(TAG, "checkBleGattDevice: not we wanted:" + device.getName());
                    }
                }
            }
            return null;
        }
        Log.w(TAG, "checkBleGattDevice: no bonded device matched");
        return null;
    }

    public static Set<BluetoothDevice> getBondedBleDevices(@NonNull Application context) {
        BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
        if (null == bluetoothManager) {
            return null;
        }
        BluetoothAdapter adapter = bluetoothManager.getAdapter();
        return adapter.getBondedDevices();
    }

    public static BluetoothDevice getTargetBondedBleDevice(@NonNull Application context, String name) {
        Log.d(TAG, "getTargetBondedBleDevice: " + name);
        if (TextUtils.isEmpty(name)) {
            return null;
        }

        Set<BluetoothDevice> bondedDevices = getBondedBleDevices(context);
        if (null != bondedDevices && bondedDevices.size() > 0) {
            for (BluetoothDevice bluetoothDevice : bondedDevices) {
                if (name.equals(bluetoothDevice.getName())) {
                    return bluetoothDevice;
                }
            }
        }
        return null;
    }

    public static RemoteDevice checkBleNodeDevice(@NonNull Application c) {
        Log.d(TAG, "checkBleNodeDevice: ");
        int connectState = RcNativeProcessJni.native_device_state();
        Log.d(TAG, "checkBleDevice: connectState = " + connectState);
        if (connectState > 0) {
            return getNanoBleRemoteDevice();
        } else {
            Log.w(TAG, "checkBleDevice: device check connect failed");
        }
        return null;
    }

    private static RemoteDevice getNanoBleRemoteDevice() {
        RemoteDevice remoteDevice = new RemoteDevice();
        remoteDevice.setVid(RcPrvdConst.NANO_BLE_DEFAULT_VID);
        remoteDevice.setPid(RcPrvdConst.NANO_BLE_DEFAULT_PID);
        remoteDevice.setDevName(RcPrvdConst.NANO_BLE_DEFAULT_NAME);
        remoteDevice.setDeviceType(RemoteDevice.RcDevType.BLE);
        remoteDevice.setDataTransferMode(RemoteDevice.DataTransferMode.BLE_DEV_NODE);
        return remoteDevice;
    }

    public static RemoteDevice checkUsbDevice(@NonNull Application context) {
        Log.d(TAG, "checkUsbDevice: ");
        HashMap<String, UsbDevice> usbDeviceList = UsbCommUtils.getUsbDeviceList(context);
        if (null == usbDeviceList || usbDeviceList.size() == 0) {
            Log.w(TAG, "checkUsbDevice: usbDeviceList is empty");
            return null;
        }
//        else {
        //debug:
        //print usb device info
//            Iterator<Map.Entry<String, UsbDevice>> iterator = usbDeviceList.entrySet().iterator();
//            while (iterator.hasNext()) {
//                Log.d(TAG, "checkUsbDevice: name ================= " + iterator.next().getKey());
//                String info = UsbCommUtils.dumpDeviceInfo(iterator.next().getValue());
//                Log.d(TAG, "checkUsbDevice: " + info);
//            }
//        }

        List<RemoteDevice> supportRemoteDeviceList = getSupportRemoteDeviceList(context);
        if (null == supportRemoteDeviceList || supportRemoteDeviceList.size() == 0) {
            Log.w(TAG, "checkUsbDevice: supportRemoteDeviceList is empty");
            return null;
        }

        for (RemoteDevice dev : supportRemoteDeviceList) {
            Iterator<Map.Entry<String, UsbDevice>> iterator = usbDeviceList.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, UsbDevice> next = iterator.next();
                Log.d(TAG, "checkUsbDevice: name ================= " + next.getKey());
                String info = UsbCommUtils.dumpDeviceInfo(next.getValue());
                Log.d(TAG, "checkUsbDevice: " + info);
                if (dev.getVid() == next.getValue().getVendorId() &&
                        dev.getPid() == next.getValue().getProductId()) {
                    return dev;
                }
            }
        }

        return null;
    }


    /**
     * 从R.xml.rc_dev_support_list配置中获取指定需要过滤遥控器设备信息集合
     *
     * @param context 上下文
     * @return 支持遥控器设备信息列表
     */
    public static List<RemoteDevice> getSupportRemoteDeviceList(@NonNull Application context) {
        List<RemoteDevice> usbFilterList = new ArrayList<>();
        try {
            XmlResourceParser xrp = context.getResources().getXml(R.xml.rc_dev_support_list);
            int event = xrp.getEventType();

            String vid = "0";
            String pid = "0";
            String deviceType = "";
            String dataTransferMode = "";
            String devName = "";
            String vendorName = "";
            while (event != XmlPullParser.END_DOCUMENT) {
                switch (event) {
                    case XmlPullParser.START_DOCUMENT:
                        Log.i(TAG, "getSupportRemoteDeviceList: start document");
                        break;
                    case XmlPullParser.START_TAG:
                        if ("rcDevice".equals(xrp.getName())) {
                            int attributeCount = xrp.getAttributeCount();
                            for (int i = 0; i < attributeCount; i++) {
                                if ("vid".equals(xrp.getAttributeName(i))) {
                                    vid = xrp.getAttributeValue(i).trim();
                                }
                                if ("pid".equals(xrp.getAttributeName(i))) {
                                    pid = xrp.getAttributeValue(i).trim();
                                }
                                if ("dataTransferMode".equals(xrp.getAttributeName(i))) {
                                    dataTransferMode = xrp.getAttributeValue(i).trim();
                                }
                                if ("devName".equals(xrp.getAttributeName(i))) {
                                    devName = xrp.getAttributeValue(i).trim();
                                }
                                if ("deviceType".equals(xrp.getAttributeName(i))) {
                                    deviceType = xrp.getAttributeValue(i).trim();
                                }
                                if ("vendorName".equals(xrp.getAttributeName(i))) {
                                    vendorName = xrp.getAttributeValue(i).trim();
                                }
                            }
                        }
                    case XmlPullParser.TEXT:
                        try {
                            if (!TextUtils.isEmpty(vendorName) && !TextUtils.isEmpty(deviceType)) {

                                RemoteDevice dev = new RemoteDevice();
                                if (RemoteDevice.RcDevType.USB.toString().equals(deviceType)) {
                                    dev.setVid(Integer.parseInt(vid));
                                    dev.setPid(Integer.parseInt(pid));
                                }
                                dev.setDataTransferMode(RemoteDevice.DataTransferMode.valueOf(dataTransferMode));
                                dev.setDevName(devName);
                                dev.setDeviceType(RemoteDevice.RcDevType.valueOf(deviceType));
                                dev.setVendorName(vendorName);

                                Log.d(TAG, "getSupportRemoteDeviceList with: dev = " + dev + "");
                                usbFilterList.add(dev);
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        break;
                    case XmlPullParser.END_TAG:
                        vid = "";
                        pid = "";
                        deviceType = "";
                        dataTransferMode = "";
                        devName = "";
                        vendorName = "";
                        break;
                    default:
                        break;
                }
                event = xrp.next();
            }
        } catch (XmlPullParserException | IOException e) {
            e.printStackTrace();
            return null;
        }
        return usbFilterList;
    }


}
